#include "Lexer.h"

#include <string>
//#include <string.h>

// #include <iostream>

using namespace neiderra::core;
// using namespace neiderra::core::io;
using namespace neiderra::utils::lexer;

using std::string;

Lexer::Lexer(Core* core, iInputStream* input): Base(core)
{
	pos = oldpos = cline_ = 0;
	input_ = input;
	buf_ = new char[input_->size()];
	input_->read(buf_, input_->size());
	cs_ = csDefault;
}

Lexer::Lexer(Core* core): Base(core){
	pos = oldpos = cline_ = 0;
	input_ = 0;
	buf_ = 0;
}

Lexer::~Lexer(){
	delete[] buf_;
}

void Lexer::setInputStream(iInputStream* input){
	delete[] buf_;
	input_ = input;
	buf_ = new char[input_->size()];
	input_->read(buf_, input_->size());
	pos = oldpos = cline_ = 0;
}

Token Lexer::copyUntil(char ch)
{
// 	core->getLogger()->traceBlock("Lexer::copyUntil");
	oldpos = pos;

	Token t;
	char *buf;
	t.id = tokSPECIAL;

	int l;
	int opos = pos;
	for(l=0;(buf_[pos]!=ch) && (pos<input_->size());l++, pos++);

	//std::cout << buf_[pos] <<" special tag length = " << l << std::endl;

	buf = new char[l];
	t.value.p = buf;

	int i;
	for(i=0;opos<pos;opos++, i++)
	{
		if(buf_[pos]=='\n') cline_++;
		buf[i] = buf_[opos];
	}
	buf[i]='\0';
	//std::cout << buf << std::endl;

// 	core->getLogger()->log(string("special string: ")+string(buf));

// 	core->getLogger()->leaveBlock();
	return t;
}

int Lexer::getLine()
{
	return cline_;
}

Token Lexer::nextToken()
{
	//core->getLogger()->traceBlock("Lexer::nextToken");
	oldpos = pos;
	Token t;
	if(!input_) {t.id = tokERRTOK; return t;}
	t.id = tokERRTOK; // by default

	int size = input_->size();

	char ch, buf[256];

	while(pos<size)
	{
begin:	ch = buf_[pos];
//		std::cout << "ch = " << ch << std::endl;
		if(ch==' '||ch=='\t'||ch=='\n'||ch==13)
		{
			if(ch=='\n'||ch==13) cline_++;
			pos++;
		}
		else if(ch==';' && cs_ == csASM){
			for(;pos<size;pos++){
				if(buf_[pos]=='\n')
				{
					cline_++;
					pos++;
					goto begin;
				}
			}
		}
		else if(ch=='<' && cs_ == csXML){
			// if <!--
			if((buf_[pos+1]=='!')&&(buf_[pos+2]=='-')&&(buf_[pos+3]=='-'))	{
				pos+=4;
				for(;pos<size;pos++){
					if(buf_[pos]=='\n') cline_++;
					if(buf_[pos]=='-' && buf_[pos+1]=='-' && buf_[pos+2]=='>'){
						pos+=3;
						goto begin;
					}
				}
			}
			else goto chars;
		}
		else if(isalpha(ch))
		{
			int i=0;
			do{
				buf[i]=ch;
				ch = buf_[++pos];
				i++;
			}
			while(isalnum(ch));
			buf[i]='\0';
//			core->getLogger()->log(string("found identifier: ")+string(buf));
			t.id = tokID;
			strcpy(t.value.sval, buf);
			return t;
		}
		else if(isdigit(ch))
		{
			int i=0;
			do
			{
				buf[i]=ch;
				ch = buf_[++pos];
				i++;
			}
			while(isdigit(ch));
			buf[i]='\0';
			//t.id = (buf_[pos]==DOT)? NUM_INT:NUM_FLOAT;
/*			ch = buf_[pos];
			if(ch=='.'){
				ch = buf_[pos++];
				while(isdigit(ch))
				buf[i]=ch;
				i++;
				ch = buf_[pos++];
			}
			else {
			}
*/
			t.id = tokNUM_INTEGER;
			t.value.num_int = atoi(buf);
//			std::cout << t.value.num_int << std::endl;
			//core->getLogger()->log(string("found number: ")+string(buf));
			return t;
		}
		else {
chars:		int i=0;
			switch(ch)
			{
				case '.': t.id = tokDOT; break;
				case ',': t.id = tokCOMMA; break;
				case ':': t.id = tokDOT_DOT; break;
				case ';': t.id = tokEOS; break;
				case '<': t.id = tokLABRACKET;	break;
				case '>': t.id = tokRABRACKET; break;
				case '{': t.id = tokLFBRACKET; break;
				case '}': t.id = tokRFBRACKET; break;
				case '(': t.id = tokLBRACKET; break;
				case ')': t.id = tokRBRACKET; break;
				case '?': t.id = tokQUEST; break;
				case '=': t.id = tokASSIGN; break;
				case '+': t.id = tokPLUS; break;
				case '-': t.id = tokMINUS; break;
				case '*': t.id = tokSTAR; break;
				case '"': t.id = tokICOMMA;
					i=0;
					pos++;
					while(buf_[pos]!='"'&&pos<size)
					{
						buf[i++] = buf_[pos++];
					}
					buf[i]='\0';

					t.id = tokSTRING;
					strcpy(t.value.sval, buf);
// 					core->getLogger()->log(string("string found: ") + string(buf));
					break;
				case '$':
					t.id = tokBOBOS;
					break;

				case '/':
					t.id = tokSLASH;
					break;
				case '\\': t.id = tokBACKSLASH; break;
				default:
					//std::cout << "Undefined symbol:" << ch << std::endl;
// 					core->getLogger()->log("Undefined symbol found");
					t.id = tokERRTOK; break;
					//pos++;
			}
			pos++;
			return t;
		}

	}

	/*for(
		int i=0, readbytes=0;
		readbytes < size; i++)
	{
		readbytes = input_->read(buf, s
	}*/

	t.id = tokEOFTOK;
	pos++;
//	core->getLogger()->leaveBlock();
	return t;
}

void Lexer::skipComments(comment_styles cs)
{
	cs_ = cs;
}

void Lexer::back()
{
	//std::cout << "back(oldpos, pos): " << oldpos << ", " << pos << std::endl;
//	input_->seek(oldpos, stBegin);
	pos = oldpos;
}
